package com.genius.aspect;

import cn.hutool.core.util.StrUtil;
import com.genius.annotation.PreDataAuth;
import com.genius.core.BaseEntity;
import com.genius.core.LoginUser;
import com.genius.system.pojo.Role;
import com.genius.system.pojo.User;
import com.genius.utils.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * 数据过滤处理
 */
@Aspect
@Component
public class PreDataAuthAspect {
    /**
     * 全部数据权限
     */
    public static final String DATA_AUTH_ALL = "1";

    /**
     * 自定义数据权限
     */
    public static final String DATA_AUTH_CUSTOM = "2";

    /**
     * 本下级数据权限
     */
    public static final String DATA_AUTH_DEPT_AND_CHILD = "3";

    /**
     * 仅本级数据权限
     */
    public static final String DATA_AUTH_DEPT = "4";

    /**
     * 仅本人数据权限
     */
    public static final String DATA_AUTH_SELF = "5";

    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_AUTH = "dataAuth";

    @Before("@annotation(preDataAuth)")
    public void doBefore(JoinPoint point, PreDataAuth preDataAuth) {
        clearDataAuth(point);
        handleDataAuth(point, preDataAuth);
    }

    protected void handleDataAuth(final JoinPoint joinPoint, PreDataAuth preDataAuth) {
        // 获取当前的用户
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser != null) {
            User user = loginUser.getUser();
            // 如果是超级管理员，则不过滤数据
            if (user != null && !user.getIsRoot()) {
                dataAuthFilter(joinPoint, user, preDataAuth.deptAlias(),
                        preDataAuth.userAlias());
            }
        }
    }

    /**
     * 数据范围过滤
     * @param joinPoint 切点
     * @param user 用户信息
     * @param deptAlias 部门表别名
     * @param userAlias 用户表别名
     */
    public static void dataAuthFilter(JoinPoint joinPoint, User user, String deptAlias, String userAlias) {
        StringBuilder sqlString = new StringBuilder();

        label:
        for (Role role : user.getRoles()) {
            String dataAuth = role.getDataAuth();
            switch (dataAuth) {
                // 全部数据权限
                case DATA_AUTH_ALL:
                    break label;
                // 自定义数据权限
                case DATA_AUTH_CUSTOM:
                    sqlString.append(StrUtil.format(
                            " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
                            role.getRoleId()));
                    break;
                // 本下级数据权限
                case DATA_AUTH_DEPT_AND_CHILD:
                    sqlString.append(StrUtil.format(
                            " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
                            deptAlias, user.getDeptId(), user.getDeptId()));
                    break;
                // 仅本级数据权限
                case DATA_AUTH_DEPT:
                    sqlString.append(StrUtil.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
                    break;
                // 仅本人数据权限
                case DATA_AUTH_SELF:
                    if (StrUtil.isNotBlank(userAlias)) {
                        sqlString.append(StrUtil.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
                    } else {
                        // 数据权限为仅本人且没有userAlias别名不查询任何数据
                        sqlString.append(" OR 1=0 ");
                    }
                    break;
            }
        }

        if (StrUtil.isNotBlank(sqlString.toString())) {
            Object params = joinPoint.getArgs()[0];
            if (params instanceof BaseEntity) {
                BaseEntity baseEntity = (BaseEntity) params;
                baseEntity.getParams().put(DATA_AUTH, " AND (" + sqlString.substring(4) + ")");
            }
        }
    }

    /**
     * 拼接权限sql前先清空params.dataAuth参数防止注入
     */
    private void clearDataAuth(final JoinPoint joinPoint) {
        Object params = joinPoint.getArgs()[0];
        if (params instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity) params;
            baseEntity.getParams().put(DATA_AUTH, "");
        }
    }
}